package com.qdd.freight.config;

import com.qdd.freight.anno.Mode;
import com.qdd.freight.handler.AbstractHandler;
import org.springframework.beans.BeansException;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashMap;

/**
 * 核心类：
 * *    1.扫描处理器的实现类，创建单例对象，在springboot启动时放入容器中；
 * *    2.根据注解值找到对应处理器的字节码，从容器中取出处理器实例；
 *
 * @ClassName StrategyFactory
 * @Description TODO
 * @Author peijie
 * @Date 2019/12/8 21:15
 * @Version 1.0
 **/
@Component
@Lazy(false)
public class StrategyFactory implements CommandLineRunner, ApplicationContextAware {
    private volatile ApplicationContext applicationContext;
    private static HashMap<String, AbstractHandler> handlerStrategyMap;

    /**
     * setter方法
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 初始化工厂的处理器map
     * 从容器中获取所有已经注册过的处理器实例，以处理器的class类名作为key,
     * 实例对象作为value存入工厂的map集合中。方便以后从容器中获取不到时，可以从工厂直接获取。
     * 只执行一次
     *
     * @param args
     */
    @Override
    public void run(String... args) {
        initHandlerStrategyMap();
    }

    private void initHandlerStrategyMap() {
        //获取所有的Handler实现类Bean，存入集合
        Collection<AbstractHandler> abstractHandlers = this.applicationContext.getBeansOfType(AbstractHandler.class).values();
        //根据实现类的bean数量构建map,并将bean依次存入map
        handlerStrategyMap = new HashMap<>(abstractHandlers.size());
        abstractHandlers.forEach(handler -> {
            Class<? extends AbstractHandler> clazz = handler.getClass();
            //获取所有的注解类型值，并以类型作为key，存储实现类Bean
            Mode anno = clazz.getAnnotation(Mode.class);
            if (anno != null) {
                handlerStrategyMap.put(anno.value(), handler);
            }
        });
    }

    /**
     * 根据传入的类型，从工厂map中获取对应的处理器策略bean实例
     *
     * @param modeId
     * @return
     */
    public static AbstractHandler getHandlerBeanByType(String modeId) {
        AbstractHandler handlerInstance = handlerStrategyMap.get(modeId);
        if (handlerInstance == null) {
//            Logger.logMsg(Logger.ERROR , "请求参数异常！");
            throw new IllegalArgumentException("请输入正确的处理器类型！");
        }
        return handlerInstance;
    }
}
